package kr.jobseeker.movinavi;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;

import org.apache.http.HttpResponse;
import org.apache.http.HttpVersion;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.conn.ConnectTimeoutException;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.params.CoreProtocolPNames;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.json.JSONArray;
import org.json.JSONObject;

import android.app.Application;
import android.location.Address;
import android.location.Geocoder;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.widget.Toast;

public class MapUtility {

	/**
	 * 결과값 전송을 위한 Intent Extra 키
	 */
	final static public String RESULT = "result";
	/**
	 * 맵 검색이 실패했을 경우 Intent Extra 값
	 */
	final static public String FAIL_MAP_RESULT = "fail_map_result";
	/**
	 * 에러 Intent Extra 값
	 */
	final static public String ERROR_RESULT = "error_result";
	/**
	 * 성공 Intent Extra 값
	 */
	final static public String SUCCESS_RESULT = "success_result";
	/**
	 * 시간 지연 Intent Extra 값
	 */
	final static public String TIMEOUT_RESULT = "timeout_result";
	/**
	 * Log Client
	 */
	final static public String TAG_CLIENT = "client";
	/**
	 * Log Server
	 */
	final static public String TAG_SERVER = "server";

	/**
	 * 결과 String 값
	 */
	public String stringData;

	// 지도 검색 비동기 스레드
	private SearchThread searchThread;
	// 지도 검색 결과 전달을 위한 핸들러
	private Handler resultHandler;
	
	
	// 길찾기 비동기 스레드
	private DirectionThread directionThread;
	// 길찾기 결과 전달을 위한 핸들러
	private Handler resultHandler_d;
	
	
	// HttpClient
	private HttpClient httpclient;

	
	/**
	 * HttpClientUtil 객체 생성자
	 */
	public MapUtility() {
	}

	/**
	 * 지도 검색 요청 (Google Mapki 사용)
	 * 
	 * @param _resultHandler
	 *            결과를 받을 핸들러
	 * @param searchingName
	 *            검색어
	 * @param nearAddress
	 *            기준 주소
	 */
	public void requestMapSearch(Handler _resultHandler, String searchingName,
			String nearAddress) {
		resultHandler = _resultHandler;

		List<BasicNameValuePair> qparams = new ArrayList<BasicNameValuePair>();
		qparams.add(new BasicNameValuePair("q", searchingName)); // 검색어
		qparams.add(new BasicNameValuePair("output", "json"));// 결과포멧 - json
		qparams.add(new BasicNameValuePair("mrt", "yp"));
		qparams.add(new BasicNameValuePair("hl", "ko")); // 언어
		qparams.add(new BasicNameValuePair("radius", "18.641")); // 검색반경 30km,
																	// miles =
																	// kilometers
																	// / 1.60934
		qparams.add(new BasicNameValuePair("num", "10")); // 검색갯수
		qparams.add(new BasicNameValuePair("near", nearAddress));
		searchThread = new SearchThread(
				qparams.toArray(new BasicNameValuePair[qparams.size()]));
		searchThread.start();

	}

	// 지도 검색 스레드
	private class SearchThread extends Thread {
		private String parameters;

		public SearchThread(NameValuePair[] _nameValues) {
			parameters = encodeParams(_nameValues);
		}

		public void run() {
			httpclient = new DefaultHttpClient();
			try {
				HttpGet get = new HttpGet();
				get.setURI(new URI("http://maps.google.co.kr?" + parameters));
				Log.i(TAG_CLIENT, "http://maps.google.co.kr?" + parameters);
				// 5초 응답시간 타임아웃
				HttpParams params = httpclient.getParams();
				params.setParameter(CoreProtocolPNames.PROTOCOL_VERSION,
						HttpVersion.HTTP_1_1);
				HttpConnectionParams.setConnectionTimeout(params, 10000);
				HttpConnectionParams.setSoTimeout(params, 10000);
				httpclient.execute(get, responseSearchHandler);

			} catch (ConnectTimeoutException e) {
				Message message = resultHandler.obtainMessage();
				Bundle bundle = new Bundle();
				bundle.putString(RESULT, TIMEOUT_RESULT);
				message.setData(bundle);
				resultHandler.sendMessage(message);
				stringData = e.toString();

			} catch (Exception e) {

				Message message = resultHandler.obtainMessage();
				Bundle bundle = new Bundle();
				bundle.putString(RESULT, ERROR_RESULT);
				message.setData(bundle);
				resultHandler.sendMessage(message);
				stringData = e.toString();
			} finally {
				httpclient.getConnectionManager().shutdown();
			}
		}
	}

	// 파라메터들을 GET 형식으로 묶어줌
	private String encodeParams(NameValuePair[] parameters) {
		StringBuilder sb = new StringBuilder();

		for (int i = 0; i < parameters.length; i++) {
			sb.append(parameters[i].getName());
			sb.append('=');
			sb.append(parameters[i].getValue().replace(" ", "+"));
			if (i + 1 < parameters.length)
				sb.append('&');
		}

		return sb.toString();
	}

	// 지도검색 결과 핸들러
	private ResponseHandler<String> responseSearchHandler = new ResponseHandler<String>() {

		private String jsonString;

		@Override
		public String handleResponse(HttpResponse response)
				throws ClientProtocolException, IOException {
			StringBuilder sb = new StringBuilder();
			try {
				InputStreamReader isr = new InputStreamReader(response
						.getEntity().getContent(), "EUC-KR");
				BufferedReader br = new BufferedReader(isr);
				for (;;) {
					String line = br.readLine();
					if (line == null)
						break;
					sb.append(line + '\n');
				}
				br.close();

				String jsonString = sb.toString().substring(9);// while(1); 문자
																// 지우기
				Log.d(TAG_SERVER, jsonString);
				JSONObject jj = new JSONObject(jsonString);
				JSONObject overlays = jj.getJSONObject("overlays");
				JSONArray markers = overlays.getJSONArray("markers");
				if (markers != null) {

					ArrayList<String> searchList = new ArrayList<String>();	// 검색 결과의 (주소, 위도, 경도) 저장
					String lat, lon;
					String address;
					for (int i = 0; i < markers.length(); i++) {
						address = markers.getJSONObject(i).getString("laddr");
						lat = markers.getJSONObject(i).getJSONObject("latlng")
								.getString("lat");
						lon = markers.getJSONObject(i).getJSONObject("latlng")
								.getString("lng");
						// 주소, 위도, 경도 순으로 저장함.
						searchList.add(address);
						searchList.add(lat);
						searchList.add(lon);
					}
					Message message = resultHandler.obtainMessage();
					Bundle bundle = new Bundle();
					bundle.putString(RESULT, SUCCESS_RESULT);
					bundle.putStringArrayList("searchList", searchList);
					message.setData(bundle);
					resultHandler.sendMessage(message);
					
				} else {
					Message message = resultHandler.obtainMessage();
					Bundle bundle = new Bundle();
					bundle.putString(RESULT, FAIL_MAP_RESULT);
					message.setData(bundle);
					resultHandler.sendMessage(message);

					stringData = "JSon >> \n" + sb.toString();
					return stringData;
				}

			} catch (Exception e) {

				Message message = resultHandler.obtainMessage();
				Bundle bundle = new Bundle();
				bundle.putString(RESULT, ERROR_RESULT);
				message.setData(bundle);
				resultHandler.sendMessage(message);

				stringData = "JSon >> \n" + e.toString();
				return stringData;
			}

			stringData = jsonString;
			return stringData;
		}
	};
	
	
	/**
	 * 길찾기 요청 (Google Mapki 사용)
	 * 
	 * @param _resultHandler_d
	 *            결과를 받을 핸들러
	 * @param startAddr
	 *            출발지 주소
	 * @param destAddr
	 *            도착지 주소
	 * @param mode
	 *            이동 수단 ( 운전, 도보, 자전거 등)
	 */	
	public void requestGetDirection(Handler _resultHandler_d, String startAddr, String destAddr) {
		resultHandler_d = _resultHandler_d;

		List<BasicNameValuePair> qparams = new ArrayList<BasicNameValuePair>();		
		qparams.add(new BasicNameValuePair("hl", "ko")); // 언어
		qparams.add(new BasicNameValuePair("origin", startAddr));
		qparams.add(new BasicNameValuePair("destination", destAddr));
		qparams.add(new BasicNameValuePair("sensor", "false"));
		qparams.add(new BasicNameValuePair("mode", "transit"));	
		qparams.add(new BasicNameValuePair("departure_time", String.valueOf(System.currentTimeMillis()/1000)));
		
		directionThread = new DirectionThread(
				qparams.toArray(new BasicNameValuePair[qparams.size()]));
		directionThread.start();

	}
	
	// 길찾기 스레드 
	private class DirectionThread extends Thread {
		private String parameters;

		public DirectionThread(NameValuePair[] _nameValues) {
			parameters = encodeParams(_nameValues);
		}

		public void run() {
			httpclient = new DefaultHttpClient();
			try {
				HttpGet get = new HttpGet();
				get.setURI(new URI("http://maps.googleapis.com/maps/api/directions/json?" + parameters));
				Log.i(TAG_CLIENT, "http://maps.googleapis.com/maps/api/directions/json?" + parameters);
				Log.e("결과", "http://maps.googleapis.com/maps/api/directions/json?" + parameters);
				
				//	http://maps.googleapis.com/maps/api/directions/json?origin=Toronto&destination=Montreal&sensor=false&avoid=highways&mode=bicycling
				
				// 5초 응답시간 타임아웃
				HttpParams params = httpclient.getParams();
				params.setParameter(CoreProtocolPNames.PROTOCOL_VERSION, HttpVersion.HTTP_1_1);
				HttpConnectionParams.setConnectionTimeout(params, 10000);
				HttpConnectionParams.setSoTimeout(params, 10000);
				httpclient.execute(get, getDirectionHandler);		// 핸들러로 해당 주소 핸들

			} catch (ConnectTimeoutException e) {
				Message message = resultHandler_d.obtainMessage();
				Bundle bundle = new Bundle();
				bundle.putString(RESULT, TIMEOUT_RESULT);
				message.setData(bundle);
				resultHandler_d.sendMessage(message);
				stringData = e.toString();

			} catch (Exception e) {

				Message message = resultHandler_d.obtainMessage();
				Bundle bundle = new Bundle();
				bundle.putString(RESULT, ERROR_RESULT);
				message.setData(bundle);
				resultHandler_d.sendMessage(message);
				stringData = e.toString();
			} finally {
				httpclient.getConnectionManager().shutdown();
			}
		}
	}
	
	
	// 길찾기 결과 핸들러
	private ResponseHandler<String> getDirectionHandler = new ResponseHandler<String>() {

		private String jsonString;
		ArrayList<DirInfo> dirInfoList = new ArrayList<DirInfo>();	// 길찾기 전체 요약 정보  저장
		ArrayList<Steps> dirStepList = new ArrayList<Steps>();		// 길찾기 세부 과정 저장
	
		@Override
		public String handleResponse(HttpResponse response) throws ClientProtocolException, IOException {
			StringBuilder sb = new StringBuilder();
			try {
				InputStreamReader isr = new InputStreamReader(response.getEntity().getContent(), "UTF-8");
				BufferedReader br = new BufferedReader(isr);
				for (;;) {
					String line = br.readLine();
					if (line == null)
						break;
					sb.append(line + '\n');
				}
				br.close();

				// json 파싱하는 부분!
				String jsonString = sb.toString();
				Log.d(TAG_SERVER, jsonString);
				
				//Tranform the string into a json object
				JSONObject jj = new JSONObject(jsonString);
				JSONObject routes =  jj.getJSONArray("routes").getJSONObject(0);
				JSONObject legs = routes.getJSONArray("legs").getJSONObject(0);
				JSONArray steps = legs.getJSONArray("steps");
			
				if (legs != null) {					
					String distance, duration;
					String end_location_lat, end_location_lng;
					String start_location_lat, start_location_lng;
					
					distance = legs.getJSONObject("distance").getString("text");
					duration = legs.getJSONObject("duration").getString("text");
								
					end_location_lat = legs.getJSONObject("end_location").getString("lat");
					end_location_lng = legs.getJSONObject("end_location").getString("lng");

					start_location_lat = legs.getJSONObject("start_location").getString("lat");
					start_location_lng = legs.getJSONObject("start_location").getString("lng");
	
					DirInfo di = new DirInfo(distance, duration, 
							end_location_lat, end_location_lng,
							start_location_lat, start_location_lng
							);
					dirInfoList.add(di);	
				}
				
				// 경로 파싱
				if (steps != null) {
					Log.d("결과", "steps*** 진입");
					
					String distance, duration;
					String html_instructions;
//					String maneuver;
					String travel_mode;
					String end_location_lat, end_location_lng;
					String start_location_lat, start_location_lng;
				
					Log.d("스텝스", String.valueOf(steps.length()));
										
					for (int i = 0; i < steps.length(); i++) {
										
						distance = steps.getJSONObject(i).getJSONObject("distance").getString("text");
						duration = steps.getJSONObject(i).getJSONObject("duration").getString("text");
						html_instructions = steps.getJSONObject(i).getString("html_instructions");
						end_location_lat = steps.getJSONObject(i).getJSONObject("end_location").getString("lat");
						end_location_lng = steps.getJSONObject(i).getJSONObject("end_location").getString("lng");
						start_location_lat = steps.getJSONObject(i).getJSONObject("start_location").getString("lat");
						start_location_lng = steps.getJSONObject(i).getJSONObject("start_location").getString("lng");
						travel_mode = steps.getJSONObject(i).getString("travel_mode");
							
						Steps st = new Steps(distance, duration, 
								end_location_lat, end_location_lng,
								html_instructions,
								start_location_lat, start_location_lng,
								travel_mode
								);
						dirStepList.add(st);						
					}

					Message message = resultHandler_d.obtainMessage();
					Bundle bundle = new Bundle();
					bundle.putString(RESULT, SUCCESS_RESULT);
					bundle.putParcelableArrayList("dirInfoList", dirInfoList);
					bundle.putParcelableArrayList("dirStepList", dirStepList);
					message.setData(bundle);
					resultHandler_d.sendMessage(message);
				} else {
					Message message = resultHandler_d.obtainMessage();
					Bundle bundle = new Bundle();
					bundle.putString(RESULT, FAIL_MAP_RESULT);
					message.setData(bundle);
					resultHandler_d.sendMessage(message);
					stringData = "JSon >> \n" + sb.toString();
					return stringData;
				}

			} catch (Exception e) {

				Message message = resultHandler.obtainMessage();
				Bundle bundle = new Bundle();
				bundle.putString(RESULT, ERROR_RESULT);
				message.setData(bundle);
				resultHandler.sendMessage(message);

				stringData = "JSon >> \n" + e.toString();
				return stringData;
			}

			stringData = jsonString;
			return stringData;
		}
	};
	
	
}
